
#include <stdio.h>
#include <libavutil/log.h>
#include <libavutil/pixfmt.h>
#include <libavcodec/version.h>

#if LIBAVCODEC_VERSION_MAJOR < 58
int main()
{
    fprintf(stderr,"libavcodec version %d.%d.%d,version require >= 58\n", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR,LIBAVCODEC_VERSION_MICRO);
    fprintf(stderr,"COUNT|%f|0|fps\n",0.0);
    return 0;
}
#else
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#include "device.h"
#include "utils.h"

extern int hwdecode(astring dec_type, astring filename, astring outdir, int dump_image_count);

extern int swdecode(astring filename, astring outdir, int dump_file_count);

extern void set_ffmpeg_log(int level);

extern float compare_dir_image(astring src_path, astring dst_path, int width, int height);

extern int prepare_hwdec(astring hw_type);

extern int get_ff_lib_version(int *libavcodec_ver, int *libavutil_ver, int *libavformat_ver);

extern int hwencode(int width, int height, int pixfmt, astring codec, astring raw_image, astring enc_video, astring dec_dir, int drm_mode);

int g_vaapi_use_drm = 0;

typedef struct _MainContext {
#define STR_LENGTH 256
    int ffmpeg_log;
    char test[STR_LENGTH];
    char type[STR_LENGTH];
    char clips[STR_LENGTH];
    int width;
    int height;
    int pixfmt;
    char swimage[STR_LENGTH];
    char hwimage[STR_LENGTH];
    char outfile[STR_LENGTH];
    char codecname[64];
} MainContext;

static int print_help(void) {
  printf("video test <options>\n");
  printf("   --test -t <hwdec(vaapi or vdpau),hwencode,swdec or data comapre>,default hwdec\n");
  printf("   --type -p <vaapi or vdpau>,default vaapi,only valid in hwdec test\n");
  printf("   --clips -c <input clip file>,default None\n");
  printf("   --log -l <set ffmpeg log level>,TRACE(56),DEBUG(48),VERBOSE(40),INFO(32),WARNING(24),ERROR(16)\n");
  printf("   --size -s <wxh>,compare image size,default 3840x2160/\n");
  printf("   --pixfmt -f <yuyv/yuyv422, nv12, I420/yuv420p> input yuv format, default yuv420p\n");
  printf("   --swimage <swdecode image file>,only valid  in data compare test\n");
  printf("   --hwimage <hwdecode image file>,only valid in data compare test\n");
  printf("   --output -o <out clip file>,default None\n");
  printf("   --codecname -n <codec name>,default None\n");
  printf("   --vaapi-drm -d, vaapi use drm, default x11\n");
  return 0;
}

static MainContext* processCmdline(int argc, char* argv[]) {
  static MainContext mainCtx = {};
  mainCtx.ffmpeg_log = AV_LOG_INFO;
  mainCtx.pixfmt = AV_PIX_FMT_YUV420P;
  int c;
  const struct option long_opts[] = {{"help", no_argument, NULL, 0},
                                     {"test", required_argument, NULL, 1},
                                     {"clips", required_argument, NULL, 2},
                                     {"swimage", required_argument, NULL, 3},
                                     {"hwimage", required_argument, NULL, 4},
                                     {"size", required_argument, NULL, 5},
                                     {"type", required_argument, NULL, 6},
                                     {"output", required_argument, NULL, 'o'},
                                     {"codecname", required_argument, NULL, 'n'},
                                     {"vaapi-drm", no_argument, NULL, 'd'},
                                     {"log", required_argument, NULL, 'l'},
                                     {"pixfmt", required_argument, NULL, 'f'},
                                     {NULL, no_argument, NULL, 0}};
  int long_index;

  while ((c = getopt_long_only(argc, argv, "dt:c:s:f:l:p:o:n:h::?", long_opts,
                               &long_index)) != EOF) {
    switch (c) {
      case 't':
      case 1 :
        strcpy(mainCtx.test,optarg);
        break;
      case 2:
      case 'c':
        strcpy(mainCtx.clips,optarg);
        break;
      case 3:
        strcpy(mainCtx.swimage,optarg);
        break;
      case 4:
        strcpy(mainCtx.hwimage,optarg);
        break;
      case 'l':
        mainCtx.ffmpeg_log=atoi(optarg);
        break;
      case 's':
      case 5:
        {
            sscanf(optarg,"%dx%d",&mainCtx.width,&mainCtx.height);
        }
        break;
      case 6:
      case 'p':
        strcpy(mainCtx.type,optarg);
        break;
      case 'o':
        strcpy(mainCtx.outfile,optarg);
        break;
      case 'n':
        strcpy(mainCtx.codecname,optarg);
        break;
      case 'd':
        g_vaapi_use_drm = 1;
        break;
      case 'f':
        if (0 == strcmp("yuv420p", optarg) || 0 == strcmp("i420", optarg))
          mainCtx.pixfmt = AV_PIX_FMT_YUV420P;
        else if (0 == strcmp("nv12", optarg))
          mainCtx.pixfmt = AV_PIX_FMT_NV12;
        else if (0 == strcmp("yuyv422", optarg) || 0 == strcmp("yuyv", optarg))
          mainCtx.pixfmt = AV_PIX_FMT_YUYV422;
        else {
          perror("invalid input pixfmt");
          exit(1);
        }
        break;
      case 0:
      case '?':
      case 'h':
        print_help();
        exit(0);
        break;
      default:
        print_help();
        exit(0);
        break;
    }
  }
  return &mainCtx;
}


char* check_and_mkdir(char* path,char*real_path)
{
  if (strlen(path)) {
    realpath(path, real_path);
    if (access(real_path, F_OK)) mkdir(path, 0755);
    return real_path;
  }
  return NULL;
}
void print_ffmpeg_version()
{
  int libavcodec_ver = 0, libavutil_ver = 0, libavformat_ver = 0;
  int major_ver = 0, mini_ver = 0, micro_ver = 0;
  get_ff_lib_version(&libavcodec_ver, &libavutil_ver, &libavformat_ver);
  major_ver = (libavcodec_ver >> 16) & 0xff;
  mini_ver = (libavcodec_ver >> 8) & 0xff;
  micro_ver = (libavcodec_ver)&0xff;
  printf("libavcodec version %d.%d.%d .\n", major_ver, mini_ver, micro_ver);
  major_ver = (libavutil_ver >> 16) & 0xff;
  mini_ver = (libavutil_ver >> 8) & 0xff;
  micro_ver = (libavutil_ver)&0xff;
  printf("libavutil version %d.%d.%d .\n", major_ver, mini_ver, micro_ver);
  major_ver = (libavformat_ver >> 16) & 0xff;
  mini_ver = (libavformat_ver >> 8) & 0xff;
  micro_ver = (libavformat_ver)&0xff;
  printf("libavformat version %d.%d.%d .\n", major_ver, mini_ver,
         micro_ver);
}

int main(int argc, char **argv)
{
#define DECODE_DUMP_FIEL_NUM 20
    MainContext *mainCtx=processCmdline(argc,argv);
    set_ffmpeg_log(mainCtx->ffmpeg_log);
    print_ffmpeg_version();
    char real_path[265] = {};
    if (load_card_config("vendorconfig.ini") < 0)
    {
        fprintf(stderr, "load_card_config cardconfig.ini error.\n");
        return -1;
    }

    if (!strncasecmp(mainCtx->test, "hwdec", 5)) {
      if (!strncasecmp(mainCtx->type, "vaapi", 5) ||
          !strncasecmp(mainCtx->type, "vdpau", 5)) {
        prepare_hwdec(mainCtx->type);
        char* path = check_and_mkdir(mainCtx->hwimage,real_path);
        if (hwdecode(mainCtx->type, mainCtx->clips, path, DECODE_DUMP_FIEL_NUM) < 0)
          fprintf(stderr, "COUNT|%f|0|fps\n", 0.0);
      }
    }
    if(!strncasecmp(mainCtx->test,"swdec",5)){
      char* path = check_and_mkdir(mainCtx->swimage,real_path);
      if (swdecode(mainCtx->clips, path, DECODE_DUMP_FIEL_NUM) < 0)
        fprintf(stderr, "COUNT|%f|0|fps\n", 0.0);
    }
    if(!strncasecmp(mainCtx->test,"cmp",3)){
        char sw_path[265] = {};
        char hw_path[265] = {};
        prepare_hwdec(mainCtx->type);
        char* path = check_and_mkdir(mainCtx->hwimage,real_path);
        if(hwdecode(mainCtx->type,mainCtx->clips,path,DECODE_DUMP_FIEL_NUM)){
          fprintf(stderr,"COUNT|%f|0|fps\n",0.0);
          return 0;
        }
        path = check_and_mkdir(mainCtx->swimage,sw_path);
        if(swdecode(mainCtx->clips,path,DECODE_DUMP_FIEL_NUM))
        {
          fprintf(stderr,"COUNT|%f|0|fps\n",0.0);
          return 0;
        }
        float similarity=compare_dir_image(sw_path,hw_path,mainCtx->width,mainCtx->height);
        fprintf(stderr,"COUNT|%f|0|fps\n",similarity);
    }
    if(!strncasecmp(mainCtx->test,"test",4)){
        prepare_hwdec("vaapi");
        prepare_hwdec("vdpau");
        fprintf(stderr,"COUNT|%f|0|fps\n",1.0);
    }

    if(!strncasecmp(mainCtx->test,"hwencode",8)){
        prepare_hwdec("vaapi");
        char* path = check_and_mkdir("./checkout", real_path);
        int ret = hwencode(mainCtx->width, mainCtx->height, mainCtx->pixfmt, mainCtx->codecname,
                           mainCtx->clips, mainCtx->outfile, path, g_vaapi_use_drm);
        if (ret < 0) {
            fprintf(stderr, "hwencode run error, ret = %d.\n", ret);
        }
    }

    if (card_config_info)
    {
        free(card_config_info);
        card_config_info = NULL;
    }
    return 0;
}
#endif
